package com.zhongge.book;

import com.zhongge.constant.Constant;
import com.zhongge.utils.AnalyzingBook;

import java.time.Instant;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.temporal.ChronoUnit;
import java.util.Arrays;
import java.util.Scanner;

/**
 * @ClassName Library
 * @Description TODO 书架类
 * 注意：本书架 管理员和普通用户都可以访问 但是记住：
 *          他们访问的是同一个书架，所以我们书架类我们使用单例模式
 *          这个类本质是一个模拟ArrayList集合的
 * @Author zhongge
 * @Version 1.0
 */
@SuppressWarnings("all")
public class Library {
    //组合图书
    Book[] books;//存放图书
    int bookCount;//当前数组中有效元素个数

    //输入对象
    Scanner scanner = new Scanner(System.in);
    //将library对象进行单例模式化
    private static Library library;//单线程下的饿汉式

    //构造方法对books和bookCount进行初始化
    /**
     * 为什么不直接将books和bookCount进行初始化？？？
     *  我们说了：在有书架的时候就将数据加载进来，那么加载进来的数据是存储在books数组中的
     *  好的，问题来了：books数组有多大?
     *      我说：假设初识为5，但是万一加载数据的时候，文件中有10本书怎么办？？
     *      所以books容量和bookCount是有变化的，因此将这个变化的初始化 封装成一个函数
     */
    //构造函数私有化
    private Library() {
        //初始化books和bookCount
        loadAllBook();
    }

    //提供方法给外部提供实例
    public static Library getLibraryInstance() {
        if (library == null) {
            return new Library();
        } else {
           return library;
        }
    }

    public int getBookCount() {
        return bookCount;
    }

    public void setBookCount(int bookCount) {
        this.bookCount = bookCount;
    }

    //有书架的时候是不是将数据也加载进来？==》此时就是需要去设计工具类了

    /**
     * 加载所有的书
     */
    private void loadAllBook() {
        //首先得有一个books数组用于存放到时候在文件中加载进来的数据
        //我这个数组是必有的，哪怕数据为空，对books初始化也为5
        books = new Book[Constant.DEFAULT_CAPACITY];
        bookCount = 0;
        //由于加载数据他是可能返回null的、此时用一个临时变量tmpBooks接受后做判断
        Book[] tmpBooks = AnalyzingBook.loadBook(Constant.BOOK_FILE_NAEM);
        if (tmpBooks == null) {
            return;
        } else {
            if (tmpBooks.length > 5) {
                books = new Book[tmpBooks.length];
                //将数据拷贝进去
                for (int i = 0; i < tmpBooks.length; i++) {
                    books[i] = tmpBooks[i];
                }
                //最后将数据有效个数更新
                bookCount = tmpBooks.length;
            } else {
                //将数据拷贝进去
                for (int i = 0; i < tmpBooks.length; i++) {
                    books[i] = tmpBooks[i];
                }
                //最后将数据有效个数更新
                bookCount = tmpBooks.length;
            }
        }
    }

    /**
     * 将所有数据写入文件
     */
    private void storageAllBook() {
        AnalyzingBook.storeBook(books, Constant.BOOK_FILE_NAEM);
    }

    /********************操作books中数据的各种方法*************************/
    /**
     * 扩容
     */
    private void grow() {
        Book[] tmp = new Book[books.length * 2];//扩容两倍
        for (int i = 0; i < books.length; i++) {
            tmp[i] = books[i];
        }
        books = tmp;
    }
    //上架图书
    public void addBook(Book book) {
        //实现真正的添加图书到books数组中
        //首先进来的话先判断满 ==》和动态数组的实现一样
        System.out.println("正在添加书籍...");
        if (bookCount >= books.length) {
            //需要扩容
            grow();
        }
        //然后将数据添加
        books[bookCount] = book;

        //这里不要急着将bookCount++
        //因为此时你需要对当前元素进行id设置
        // |  |  |  |
        //0  1  2 countBook

        //对书本id进行设计
        //如果bookCount是0==》书本id是1
        if (bookCount == 0) {
            books[bookCount].setBookId(1);
        } else {
            //如果不是第一本书就找出最后一本书 并将最后一本书的id+1作为所加书本的id
            books[bookCount].setBookId(books[bookCount - 1].getBookId() + 1);
        }

        bookCount++;

        //最后将books中的所有书籍信息更新到文件中存储起来
        storageAllBook();
        System.out.println("书籍添加成功！！ 该书籍的名字为" + book.getTitle());
    }
    //修改图书

    /**
     * 修改书名
     * @param book 待修改的书
     * @param bookName 书名
     */
    public void modifyBookName(Book book, String bookName) {
        /*
        我们在AdminUser中将所有的业务判断框架处理好，让后就在这里直接操作
         */

        //修改名字
        book.setTitle(bookName);

        //将最新信息写入文件
        storageAllBook();

        System.out.println("更新书籍成功，更新后书籍信息如下：");
        System.out.println(book);
    }

    /**
     * 修改作者
     * @param book 待修改的书
     * @param author 作者
     */
    public void modifyBookAuthor(Book book, String author) {
        //修改作者
        book.setAuthor(author);

        //将最新信息写入文件
        storageAllBook();

        System.out.println("更新书籍成功，更新后书籍信息如下：");
        System.out.println(book);
    }

    /**
     * 修改类型
     * @param book 待修改的书
     * @param type 类型
     */
    public void modifyBookType(Book book, String type) {
        //修改类型
        book.setType(type);

        //将最新信息写入文件
        storageAllBook();

        System.out.println("更新书籍成功，更新后书籍信息如下：");
        System.out.println(book);
    }

    /**
     * 修改出版年份
     * @param book 待修改的书
     * @param publishYear 出版年份
     */
    public void modifyBookPublishYear(Book book, int publishYear) {
        //修改出版时间
        book.setPublishYear(publishYear);

        //将最新信息写入文件
        storageAllBook();

        System.out.println("更新书籍成功，更新后书籍信息如下：");
        System.out.println(book);
    }

    /**
     * 修改上架时间
     * @param book 待修改的书
     * @param shelfDate 上架时间
     */
    public void modifyBookShelfDate(Book book, LocalDate shelfDate) {
        //修改上架时间
        book.setShelfDate(shelfDate);

        //将最新信息写入文件
        storageAllBook();

        System.out.println("更新书籍成功，更新后书籍信息如下：");
        System.out.println(book);
    }

    /**
     * 根据书籍Id 查找对应的书籍
     * @param bookId
     * @return
     */
    public Book searchById(int bookId) {

        for (int i = 0; i < bookCount; i++) {
            if(books[i].getBookId() == bookId) {
                return books[i];
            }
        }
        return null;
    }

    //下架图书

    /**
     * 根据图书id删除图书
     * @param bookId 图书id
     */
    public void deleteBook(int bookId) {
        //首先加载所有的书籍
        loadAllBook();

        //然后为了删除books中对应的bookId下的书籍就根据id找到该书在books数组中的下标
        int index = searchByIdReturnIndex(bookId);

        if(index == -1) {
            System.out.println("没有你要删除的图书...");
            return;
        }

        //如果程序走到这里书名书籍存在
        //开始从左到右一次向前覆盖 将书籍删除
        for (int i = index; i < bookCount - 1; i++) {
            books[i] = books[i + 1];
        }

        //将最后一个书籍设置为null
        /*books[bookCount] = null;//ArrayIndexOutOfBoundsException越界
        * 原因：因为bookCount始终指向的是数组中最后一个有效元素的下一个此时他就是空的
        * */

        books[bookCount - 1] = null;

        //书籍有效个数-1
        bookCount--;

        //将最新的数据存于文件
        storageAllBook();
    }

    /**
     * 根据书本id得到书本所在的下标
     * @param bookId 书本id
     * @return
     */
    private int searchByIdReturnIndex(int bookId) {
        loadAllBook();
        for (int i = 0; i < bookCount; i++) {
            Book book = books[i];
            if(book.getBookId()==bookId) {
                return i;
            }
        }
        return -1;
    }

    //统计借阅次数
    public void borrowCount() {
        loadAllBook();//每一次数据的查询都是要进行最新数据的加载
        for (int i = 0; i < bookCount; i++) {
            Book book = books[i];
            System.out.println("书籍名称："+book.getTitle()+" 借阅次数："+book.getBorrowCount());
        }
    }
    //查看最受欢迎的前n本书
    public void popularBook(int n) {

        loadAllBook();

        //把所有书籍放在 临时数据 进行排序
        /**
         * 注意：排序的时候 Arrays.sort底层调用的是compareTo 所以得去实现 Book类中的compareTo方法
         */
        Book[] tmp = new Book[getBookCount()];
        for (int i = 0; i < getBookCount(); i++) {
            tmp[i] = books[i];
        }

        Arrays.sort(tmp);//从大 到 小的 排序

        //把前n本书拷贝到新数组
        Book[] newBooks = new Book[n];

        for (int i = 0; i < n; i++) {
            newBooks[i] = tmp[i];
        }

        //将最受欢迎的前n本书打印出来
        System.out.println("最受欢迎的前K本书如下：");
        for (int i = 0; i < n; i++) {
            Book book = newBooks[i];
            System.out.println("书名："+ book.getTitle()+" 作者："+
                    book.getTitle()+" 借阅次数："+book.getBorrowCount());
        }

    }
    //查看库存状态
    public void inventoryStatus() {
        loadAllBook();

        System.out.println("================================");
        for (int i = 0; i < bookCount; i++) {
            Book book = books[i];
            String status = book.isBorrow() ? "已借出" : "在馆"; //如果isBorrow==true ==>已借出
            System.out.println("书名："+book.getTitle()+" 目前状态："+status);
        }
        System.out.println("================================");
    }
    //10.检查并移除上架超过一年的书
    public void checkAndRemoveOldBooks() {//检查并移除书籍
        loadAllBook();
        // 获取当前时间戳
        long currentTimestamp = System.currentTimeMillis();

        // 将当前时间戳转换为 LocalDate
        LocalDate currentDate = Instant.ofEpochMilli(currentTimestamp)
                .atZone(ZoneId.systemDefault())
                .toLocalDate();


        boolean flg = false;
        for (int i = 0; i < getBookCount(); i++) {
            Book book = books[i];
            //获取当前书籍的上架时间
            LocalDate specifiedDate = book.getShelfDate();

            // 计算两个日期之间的差值（以年为单位）
            long yearsBetween = ChronoUnit.YEARS.between(specifiedDate, currentDate);

            if(yearsBetween >= 1) {
                System.out.print("图书 " + book.getTitle() + " 已经上架超过一年，是否移除？ (是/否)：");
                String response = scanner.nextLine();
                if (response.equals("是")) {
                    //确认删除调用deleteBook方法进行删除
                    deleteBook(book.getBookId());
                    i--;  // 因为后面的书已经向前移动，所以要重新检查当前索引位置
                }
                flg = true;
            }
        }
        if(!flg) {
            System.out.println("没有上架超过一年的图书！");
        }

        storageAllBook();

    }

    //借阅图书
    public void borrowBook(int bookId) {
        //主要是为了设置借阅转态为true 以及增加借阅次数
        loadAllBook();

        for (int i = 0; i < bookCount; i++) {
            Book book = books[i];
            if(book.getBookId() == bookId) {
                book.setBorrow(true);//设置借阅转态为true
                book.increaseBorrwoCount();//借阅次数+1
            }
        }

        storageAllBook();
    }
    //归还图书
    public void returnBook(int bookId) {
        //主要是为了设置借阅转态为false 以及减少借阅次数
        loadAllBook();

        for (int i = 0; i < bookCount; i++) {
            Book book = books[i];
            if(book.getBookId() == bookId) {
                book.setBorrow(false);//设置借阅转态为false
                book.reduceBorrwoCount();//借阅次数-1
            }
        }

        storageAllBook();
    }
    /**
     * 退出系统
     */
    public void exit() {
        System.out.println("系统已退出");
        System.exit(0);
    }

    /**
     * 打印图书信息
     */
    public void displayBooks() {
        //打印图书的时候需要将最新的书籍信息从文件中加载进来
        loadAllBook();
        if (books == null || this.bookCount == 0) {
            System.out.println("书架不存在 或者 书架上不存在书本");
            return;
        }
        for (int i = 0; i < this.bookCount; i++) {
            System.out.println(books[i]);//根据toString打印出来
        }
    }

    /**
     * 查找图书
     */
    public void searchBook() {
        boolean flg = false;
        System.out.println("请输入你要查找的图书名字：");
        String bookName = scanner.nextLine();
        //在这之前：需要判断books 和 books中内容是否为空
        if (books == null || this.bookCount == 0) {
            System.out.println("书架不存在 或者 书架上不存在任何一本书");
            return;
        }

        for (int i = 0; i < this.bookCount; i++) {
            if (bookName.equals(books[i].getTitle())) {
                System.out.println(books[i]);
                flg = true;
            }
        }
        //如果flg == false 说明没有这本书
        if (!flg) {
            System.out.println("没有你要找的这本书！！！");
        }
    }
}
